#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <uci.h>
#include <unistd.h>
/* 状态码 */
#define TRUE 1 //真
#define FALSE 0 //假
#define YES 1 //是
#define NO 0 //否
#define OK 1 //通过
#define ERROR 0 //错误
#define SUCCESS 1 //成功
#define UNSUCCESS 0 //失败

#define UCI_CONFIG_FILE "/etc/config/meter"
//static 







static void uci_print_value(FILE* f, const char* v)
{
    fprintf(f, "'");
    while (*v) {
        if (*v != '\'')
            fputc(*v, f);
        else
            fprintf(f, "'\\''");
        v++;
    }
    fprintf(f, "'");
}

static void uci_show_value(struct uci_option* o, bool quote)
{
    struct uci_element* e;
    bool sep = false;
    char* space;

    switch (o->type) {
    case UCI_TYPE_STRING:
        if (quote)
            uci_print_value(stdout, o->v.string);
        else
            printf("%s", o->v.string);
        printf("\n");
        break;
    case UCI_TYPE_LIST:
        uci_foreach_element(&o->v.list, e)
        {
            //            printf("%s", (sep ? delimiter : ""));
            space = strpbrk(e->name, " \t\r\n");
            if (!space && !quote)
                printf("%s", e->name);
            else
                uci_print_value(stdout, e->name);
            sep = true;
        }
        printf("\n");
        break;
    default:
        printf("<unknown>\n");
        break;
    }
}
/*
添加section，在指定的包中添加。
*/
static int uci_do_add(char* pkg, char* section)
{
    struct uci_package* p = NULL;
    struct uci_section* s = NULL;
    int ret;
    struct uci_context* ctx = uci_alloc_context(); // 申请一个UCI上下文.
    //    char* f = strdup("/etc/config/user");
    ret = uci_load(ctx, pkg, &p);
    if (ret != UCI_OK) {
        // uci_perror(ctx, "uci_load");
        goto done;
    }

    ret = uci_add_section(ctx, p, section, &s);
    if (ret != UCI_OK) {
        // uci_perror(ctx, "uci_add_section");

        goto done;
    }
    ret = uci_save(ctx, p);
    ret = uci_commit(ctx, &p, false); //提交保存更改
done:
    // if (ret != UCI_OK)
    //     uci_perror(ctx, "uci_do_add");
    // else if (s)
    //     fprintf(stdout, "%s\n", s->e.name);

    uci_unload(ctx, p); //卸载包
    uci_free_context(ctx); //释放上下文
    return ret;
}

/*
检查是否存在指定名称的包，存在返回ture，不存在返回false
*/
bool chk_package(struct uci_context* ctx, char* str)
{
    struct uci_package* p = NULL;
    struct uci_section* s = NULL;
    int ret;
    ret = uci_load(ctx, str, &p);
    if (ret != UCI_OK) {
        // uci_perror(ctx, "chk_package_false"); //
        return FALSE;
    }
    // uci_perror(ctx, "chk_package_true"); //
    return TRUE;
}

/*
检查是否存在指定的段落，存在返回ture，不存在返回false
str格式：user.@ser485net[0]
*/
bool chk_section(struct uci_context* ctx, char* str)
{
    struct uci_element* e;
    struct uci_ptr ptr;
    // ctx = uci_alloc_context(); // 申请一个UCI上下文.
    if (uci_lookup_ptr(ctx, &ptr, str, true) != UCI_OK) {
        // uci_perror(ctx, "uci_lookup_ptr");
        // uci_free_context(ctx); //释放上下文
        return FALSE;
    } else {
        e = ptr.last;

        if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
            ctx->err = UCI_ERR_NOTFOUND;
            // uci_perror(ctx, "chk_section");
            // uci_free_context(ctx); //释放上下文
            return FALSE;
        }
        // uci_perror(ctx, "chk_section");
        // uci_free_context(ctx); //释放上下文
        return TRUE;
    }
}
/*
设置ptr数据结构,返回0表示不存在，设置成功。返回1表示存在设置成功。返回-1表示设置失败。
*/
int set_ptr(struct uci_context* ctx, struct uci_ptr* ptr, char* str)
{
    if (uci_lookup_ptr(ctx, ptr, str, true) != UCI_OK) {
        return -1;
    } else {
        if (!(ptr->flags & UCI_LOOKUP_COMPLETE)) {
            ctx->err = UCI_ERR_NOTFOUND;
            return 0;
        }
        // uci_perror(ctx, "chk_section");
        // uci_free_context(ctx); //释放上下文
        return 1;
    }
}

/*
写初始化配置文件,位置/etc/config/user
package :user
section :ser485net
option  server:www.cloudeyes.cn
        server_port:60000
        ser485:/dev/ttyS0
        bps:115200
        local_port:7001
        logdir:/mnt/tfcard
section :networklte
option  usb_at:/dev/ttyUSB2
        pin_chk:yes
        pin_key:1205
        status:yes
        work_mode:2
*/
bool write_config_first(void)
{
    struct uci_package* pkg = NULL;
    struct uci_element* e;
    char *tmp, *tmp1;
    int f;
    const char* value;
    struct uci_ptr ptr;
    struct uci_context* ctx = NULL; //定义一个UCI上下文的静态变量.
    ctx = uci_alloc_context(); // 申请一个UCI上下文.
    tmp = strdup("user");
    if (chk_package(ctx, tmp) == FALSE) { //创建文件
        tmp1 = strdup("/etc/config/user");
        f = open(tmp1, O_RDWR | O_CREAT, 700); //O_TRUNC若存在长度截断为0
        close(f);
        free(tmp1);
        printf("creat!\n");
    }

    tmp1 = strdup("user.@ser485net[0]");
    if (chk_section(ctx, tmp1) == FALSE) { //创建段落section
        printf("creat section\n");
        free(tmp1);
        tmp1 = strdup("ser485net");
        uci_do_add(tmp, tmp1);
    }
    free(tmp1);

    tmp1 = strdup("user.@networklte[0]");
    if (chk_section(ctx, tmp1) == FALSE) { //创建段落section
        printf("creat section\n");
        free(tmp1);
        tmp1 = strdup("networklte");
        uci_do_add(tmp, tmp1);
    }
    free(tmp1);
    /*
option  server:www.cloudeyes.cn
        server_port:60000
        ser485:/dev/ttyS0
        bps:115200
        local_port:7001
        logdir:/mnt/tfcard
*/
    uci_free_context(ctx); //释放上下文
    ctx = uci_alloc_context(); // 申请一个UCI上下文.
    tmp1 = strdup("user.@ser485net[0].server=www.cloudeyes.cn");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);

    tmp1 = strdup("user.@ser485net[0].server_port=60000");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@ser485net[0].ser485=/dev/ttyS0");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@ser485net[0].bps=115200");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@ser485net[0].local_port=7001");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@ser485net[0].logdir=/mnt/tfcard");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    /*
section :networklte
option  usb_at:/dev/ttyUSB2
        pin_chk:yes
        pin_key:1205
        status:yes
        work_mode:2
*/
    tmp1 = strdup("user.@networklte[0].usb_at=/dev/ttyUSB2");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@networklte[0].work_mode=2");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@networklte[0].pin_chk=yes");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@networklte[0].pin_key=1205");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    tmp1 = strdup("user.@networklte[0].status=yes");
    if (set_ptr(ctx, &ptr, tmp1) == 0) {
        uci_set(ctx, &ptr);
        uci_commit(ctx, &ptr.p, false); //提交保存更改
    }
    free(tmp1);
    uci_free_context(ctx); //释放上下文
}

char* get_option(char* str)
{
    struct uci_context* ctx;
    struct uci_ptr ptr;
    struct uci_option* o;
    struct uci_element* e;
    char* data = NULL;
    ctx = uci_alloc_context(); // 申请一个UCI上下文.
    if (uci_lookup_ptr(ctx, &ptr, str, true) != UCI_OK) {
        // uci_perror(ctx, "uci_lookup_ptr");
        // uci_free_context(ctx); //释放上下文
        goto out;
    } else {
        e = ptr.last;

        if (!(ptr.flags & UCI_LOOKUP_COMPLETE)) {
            ctx->err = UCI_ERR_NOTFOUND;
            // uci_perror(ctx, "chk_section");
            // uci_free_context(ctx); //释放上下文
            goto out;
        }
        switch (e->type) {
        case UCI_TYPE_SECTION:
            printf("err:this is a section:%s\n", ptr.s->type);
            // data = strdup(ptr.s->type);
            break;
        case UCI_TYPE_OPTION:
            o = ptr.o;
            switch (o->type) {
            case UCI_TYPE_STRING:
                data = strdup(ptr.o->v.string);
                break;
            case UCI_TYPE_LIST:
                uci_foreach_element(&o->v.list, e)
                {
                    printf("%s ", e->name);
                }
                printf("\n");
                break;
            default:
                printf("<unknown>\n");
                break;
            }
            break;
        default:
            break;
            // uci_perror(ctx, "chk_section");
            // uci_free_context(ctx); //释放上下文
        }
    }
out:
    uci_free_context(ctx); //释放上下文
    return data;
}
/*********************************************
*   载入配置文件,并遍历Section.
*/
bool load_config()
{
    struct uci_package* pkg = NULL;
    struct uci_element* e;
    char* tmp;
    const char* value;
struct uci_context* ctx = NULL; //定义一个UCI上下文的静态变量.
    ctx = uci_alloc_context(); // 申请一个UCI上下文.
    if (UCI_OK != uci_load(ctx, UCI_CONFIG_FILE, &pkg)) {
        uci_perror(ctx, "uci_load error");
        printf("uci_load error\n");
        goto cleanup; //如果打开UCI文件失败,则跳到末尾 清理 UCI 上下文.
    }

    /*遍历UCI的每一个节*/
    uci_foreach_element(&pkg->sections, e)
    {
        struct uci_section* s = uci_to_section(e);

        printf("section s's type is %s.\n", s->type);

        if (!strcmp("servver", s->type)) {
            printf("this seciton is a servver.\n");
            struct uci_option* opt = uci_lookup_option(ctx, s, "value");
        }

        if (!strcmp("meter", s->type)) //this section is a meter
        {
            printf("this seciton is a meter.\n");
            if (NULL != (value = uci_lookup_option_string(ctx, s, "modbus_id"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's modbus_id is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "num_attr"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's num_attr is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "sender_id"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's sender_id is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "customer_id"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's customer_id is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "customer_name"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's customer_name is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "account_id"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's account_id is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "account_name"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's account_name is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "meter_id"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's meter_id is %s.\n", s->e.name, value);
            }
            if (NULL != (value = uci_lookup_option_string(ctx, s, "commodity"))) {
                tmp = strdup(value); //如果您想持有该变量值，一定要拷贝一份。当 pkg销毁后value的内存会被释放。
                printf("%s's commodity is %s.\n", s->e.name, value);
            }
        }
        // 如果您不确定是 string类型 可以先使用 uci_lookup_option() 函数得到Option 然后再判断.
        // Option 的类型有 UCI_TYPE_STRING 和 UCI_TYPE_LIST 两种.
    }
    uci_unload(ctx, pkg); // 释放 pkg
cleanup:
    uci_free_context(ctx);
    ctx = NULL;
}
int main(int argc, char* argv[])
{
    char *data = NULL, *tmp1 = NULL;
    write_config_first();
    tmp1 = strdup("user.@ser485net[0].server");
    if ((data = get_option(tmp1)) != NULL) {
        printf("user.@ser485net[0].server=%s\n", data);
        free(data);
    }
    // load_config();
}
